www.gusucode.com > VC++ 车牌定位与识别源码程序 > VC++ 车牌定位与识别源码程序/code/PlateReco/PlateRecoView.cpp
//Download by http://www.NewXing.com // PlateRecoView.cpp : implementation of the CPlateRecoView class // #include "stdafx.h" #include "PlateReco.h" #include "MainFrm.h" #include "DlgRecoResult.h" #include "PlateRecoDoc.h" #include "PlateRecoView.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CPlateRecoView IMPLEMENT_DYNCREATE(CPlateRecoView, CView) BEGIN_MESSAGE_MAP(CPlateRecoView, CView) //{{AFX_MSG_MAP(CPlateRecoView) ON_COMMAND(ID_LPR_platelocation, OnLPRplatelocation) ON_COMMAND(ID_LPR_plate2binarycolor, OnLPRplate2binarycolor) ON_COMMAND(ID_LPR_platenorm, OnLPRplatenorm) ON_COMMAND(ID_LPR_platecharthinning, OnLPRplatecharthinning) ON_COMMAND(ID_LPR_feature16seg, OnLPRfeature16seg) ON_COMMAND(ID_LPR_platereco, OnLPRplatereco) ON_COMMAND(ID_LPR_platepreprocessall, OnLPRplatepreprocessall) //}}AFX_MSG_MAP // Standard printing commands ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CPlateRecoView construction/destruction CPlateRecoView::CPlateRecoView() { // TODO: add construction code here for(int i = 0; i < 13; i++) { m_fCode13Sect[i] = 0.0; } for(int j = 0; j < 16; j++) { m_fCode13Sect[j] = 0.0; } m_iPlateType = 0; } CPlateRecoView::~CPlateRecoView() { } BOOL CPlateRecoView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CView::PreCreateWindow(cs); } ///////////////////////////////////////////////////////////////////////////// // CPlateRecoView drawing void CPlateRecoView::OnDraw(CDC* pDC) { // 显示等待光标 BeginWaitCursor(); // 获取文档 CPlateRecoDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // 获取DIB HDIB hDIB = pDoc->GetHDIB(); // 判断DIB是否为空 if (hDIB != NULL) { LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB); // 获取DIB宽度 int cxDIB = (int) ::DIBWidth(lpDIB); // 获取DIB高度 int cyDIB = (int) ::DIBHeight(lpDIB); ::GlobalUnlock((HGLOBAL) hDIB); CRect rcDIB; rcDIB.top = rcDIB.left = 0; rcDIB.right = cxDIB; rcDIB.bottom = cyDIB; CRect rcDest; // 判断是否是打印 if (pDC->IsPrinting()) { // 是打印,计算输出图像的位置和大小,以便符合页面 // 获取打印页面的水平宽度(象素) int cxPage = pDC->GetDeviceCaps(HORZRES); // 获取打印页面的垂直高度(象素) int cyPage = pDC->GetDeviceCaps(VERTRES); // 获取打印机每英寸象素数 int cxInch = pDC->GetDeviceCaps(LOGPIXELSX); int cyInch = pDC->GetDeviceCaps(LOGPIXELSY); // 计算打印图像大小(缩放,根据页面宽度调整图像大小) rcDest.top = rcDest.left = 0; rcDest.bottom = (int)(((double)cyDIB * cxPage * cyInch) / ((double)cxDIB * cxInch)); rcDest.right = cxPage; // 计算打印图像位置(垂直居中) int temp = cyPage - (rcDest.bottom - rcDest.top); rcDest.bottom += temp/2; rcDest.top += temp/2; } else // 非打印 { // 不必缩放图像 rcDest = rcDIB; } // 输出DIB ::PaintDIB(pDC->m_hDC, &rcDest, pDoc->GetHDIB(), &rcDIB, pDoc->GetDocPalette()); } CSize sizeTotal(1200,900); SetScrollSizes(MM_TEXT, sizeTotal); // 恢复正常光标 EndWaitCursor(); } void CPlateRecoView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); CSize sizeTotal; // TODO: calculate the total size of this view sizeTotal.cx =1200; sizeTotal.cy =900; SetScrollSizes(MM_TEXT, sizeTotal); // 获取文档 CPlateRecoDoc* pDoc = GetDocument(); // 指向DIB的指针 LPSTR lpDIB; // 锁定DIB lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB()); // 保存原图像大小 m_iWidth = ::DIBWidth(lpDIB); m_iHeight = ::DIBHeight(lpDIB); /* CScrollView::OnInitialUpdate(); CSize sizeTotal(1000,600);//::DIBWidth(lpDIB), ::DIBHeight(lpDIB)); SetScrollSizes(MM_TEXT, sizeTotal); CMainFrame* pAppFrame = (CMainFrame*) AfxGetApp()->m_pMainWnd; ASSERT_KINDOF(CMainFrame, pAppFrame); CRect rc; pAppFrame->GetClientRect(&rc); if (rc.Width() >= sizeTotal.cx && rc.Height() >= sizeTotal.cy && (sizeTotal.cx>0 || sizeTotal.cy>0)) ResizeParentToFit(FALSE); */ } ///////////////////////////////////////////////////////////////////////////// // CPlateRecoView printing BOOL CPlateRecoView::OnPreparePrinting(CPrintInfo* pInfo) { // 设置总页数为一。 pInfo->SetMaxPage(1); // default preparation return DoPreparePrinting(pInfo); } void CPlateRecoView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add extra initialization before printing } void CPlateRecoView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add cleanup after printing } ///////////////////////////////////////////////////////////////////////////// // CPlateRecoView diagnostics #ifdef _DEBUG void CPlateRecoView::AssertValid() const { CView::AssertValid(); } void CPlateRecoView::Dump(CDumpContext& dc) const { CView::Dump(dc); } CPlateRecoDoc* CPlateRecoView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CPlateRecoDoc))); return (CPlateRecoDoc*)m_pDocument; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CPlateRecoView message handlers LRESULT CPlateRecoView::OnDoRealize(WPARAM wParam, LPARAM) { ASSERT(wParam != NULL); // 获取文档 CPlateRecoDoc* pDoc = GetDocument(); // 判断DIB是否为空 if (pDoc->GetHDIB() == NULL) { // 直接返回 return 0L; } // 获取Palette CPalette* pPal = pDoc->GetDocPalette(); if (pPal != NULL) { // 获取MainFrame CMainFrame* pAppFrame = (CMainFrame*) AfxGetApp()->m_pMainWnd; ASSERT_KINDOF(CMainFrame, pAppFrame); CClientDC appDC(pAppFrame); // All views but one should be a background palette. // wParam contains a handle to the active view, so the SelectPalette // bForceBackground flag is FALSE only if wParam == m_hWnd (this view) CPalette* oldPalette = appDC.SelectPalette(pPal, ((HWND)wParam) != m_hWnd); if (oldPalette != NULL) { UINT nColorsChanged = appDC.RealizePalette(); if (nColorsChanged > 0) pDoc->UpdateAllViews(NULL); appDC.SelectPalette(oldPalette, TRUE); } else { TRACE0("\tCCh1_1View::OnPaletteChanged中调用SelectPalette()失败!\n"); } } return 0L; } ///////////////////////////////////////////////////////////////////////////// // CPlateRecoView message handlers void CPlateRecoView::OnLPRplatelocation() { // TODO: Add your command handler code here // 获取文档 CPlateRecoDoc* pDoc = GetDocument(); // 指向DIB的指针 LPSTR lpDIB; // 指向DIB象素指针 LPSTR lpDIBBits; // 锁定DIB lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB()); // 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的边缘检测,其它的可以类推) if (::DIBNumColors(lpDIB) != 256) { // 提示用户 MessageBox("目前只支持256色位图的运算!", "系统提示" , MB_ICONINFORMATION | MB_OK); // 解除锁定 ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); // 返回 return; } // 找到DIB图像象素起始位置 lpDIBBits = ::FindDIBBits(lpDIB); // 指向缓存图像的指针 LPSTR lpDst1; LPSTR lpDst2; // 指向缓存DIB图像的指针 LPSTR lpNewDIBBits1; HLOCAL hNewDIBBits1; LPSTR lpNewDIBBits2; HLOCAL hNewDIBBits2; int *pPlateLine1,*pPlateLine2; // 获取车牌位置信息 int *pPlatePosition; //循环变量 long i; long j; for(i=0;i<40;i++) m_iPlateLine[i]=0; // 指向源图像象素的指针 unsigned char * lpSrc; // 阈值 BYTE bThre; // 各个灰度值的计数 LONG lCount[256]; int temp1,temp2,iOldLeixin1,iOldLeixin2,iNum1,iNum2,iGrayCore1,iGrayCore2,iMeanGray; // 参数对话框 //CDlgBinary myDlgBinary; // 暂时分配内存,以保存新图像 hNewDIBBits1 = LocalAlloc(LHND, m_iWidth * m_iHeight); if (hNewDIBBits1 == NULL) { // 分配内存失败 return; } // 锁定内存 lpNewDIBBits1 = (char * )LocalLock(hNewDIBBits1); // 暂时分配内存,以保存新图像 hNewDIBBits2 = LocalAlloc(LHND, m_iWidth * m_iHeight); if (hNewDIBBits2 == NULL) { // 分配内存失败 return; } // 锁定内存 lpNewDIBBits2 = (char * )LocalLock(hNewDIBBits2); // 拷贝源图像到缓存图像中 lpDst1 = (char *)lpNewDIBBits1; memcpy(lpNewDIBBits1, lpDIBBits, m_iWidth * m_iHeight); lpDst2 = (char *)lpNewDIBBits2; memcpy(lpNewDIBBits2, lpDIBBits, m_iWidth * m_iHeight); // 复制经过模板运算后的图像到源图像 // memcpy(lpDIBBits, lpNewDIBBits1, m_iWidth * m_iHeight); // 更改光标形状 BeginWaitCursor(); //////////////////////////////////////////////////////// // 水平差分 if (DifferDIB(lpDIBBits, WIDTHBYTES(::DIBWidth(lpDIB) * 8), ::DIBHeight(lpDIB))) { // 设置脏标记 pDoc->SetModifiedFlag(TRUE); // 更新视图 pDoc->UpdateAllViews(NULL); } else { // 提示用户 MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION | MB_OK); } //////////////////////////////////////////////////////// // 调用HprojectDIB()函数对DIB进行水平投影 if (pPlateLine1 = HDifferProjDIB4(lpDIBBits,::DIBWidth(lpDIB), ::DIBHeight(lpDIB))) { for(int i=0;i<40;i++) { m_iPlateLine[i]=*pPlateLine1; pPlateLine1++; } // 设置脏标记 pDoc->SetModifiedFlag(TRUE); // 更新视图 pDoc->UpdateAllViews(NULL); } else { // 提示用户 MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION | MB_OK); } //////////////////////////////////////////////////////// int iLineNumber=0; for(iLineNumber=0;iLineNumber<40;iLineNumber++) { //////////////////////////////////////////////////////// // 复制原图象 memcpy(lpDIBBits, lpNewDIBBits1, m_iWidth * m_iHeight); // 设置脏标记 pDoc->SetModifiedFlag(TRUE); // 更新视图 pDoc->UpdateAllViews(NULL); // AfxMessageBox("又一次"); //////////////////////////////////////////////////////// // 边缘检测 pPlateLine2 = &m_iPlateLine[iLineNumber]; // 调用SobelDIB()函数对DIB进行边缘检测 if (PlateDIB1(lpDIBBits,::DIBWidth(lpDIB), ::DIBHeight(lpDIB),pPlateLine2)) { // 设置脏标记 pDoc->SetModifiedFlag(TRUE); // 更新视图 pDoc->UpdateAllViews(NULL); } else { // 提示用户 MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION | MB_OK); } //////////////////////////////////////////////////////// // 二值化 // 重置计数为0 for (i = 0; i < 256; i ++) { // 清零 lCount[i] = 0; } // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(m_iWidth * 8); // 计算各个灰度值的计数 for (i = 0; i < m_iHeight; i ++) { for (j = 0; j < m_iWidth; j ++) { lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j; // 计数加1 lCount[*(lpSrc)]++; } } // 计算平均灰度值 iMeanGray = 0; for(i = 1; i < 255; i++) { iMeanGray += i * lCount[i]; } iMeanGray = (int)iMeanGray / (m_iHeight * m_iWidth); // 初始的类心,可任意设定 iGrayCore1 = (int)(iMeanGray/2); iGrayCore2 = (int)(iMeanGray+(255-iMeanGray)/2); do // K-均值聚类分析 { iNum1 = 0; iNum2 = 0; temp1 = 0; temp2 = 0; iOldLeixin1 = iGrayCore1; iOldLeixin2 = iGrayCore2; for(i = 0; i < m_iHeight; i++) { for(j = 0; j < m_iWidth; j++) { lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j; if(abs(iGrayCore1-*lpSrc)<=abs(iGrayCore2-*lpSrc)) { temp1 += *lpSrc; iNum1++; } else { temp2 += *lpSrc; iNum2++; } } } iGrayCore1 = (int)(temp1/iNum1); iGrayCore2 = (int)(temp2/iNum2); }while((iGrayCore1!=iOldLeixin1)||(iGrayCore2!=iOldLeixin2)); bThre = iGrayCore2+30; // 删除对话框 // delete myDlgBinary; // 更改光标形状 BeginWaitCursor(); // 调用ThresholdTrans()函数进行阈值变换 ThresholdTrans(lpDIBBits, ::DIBWidth(lpDIB), ::DIBHeight(lpDIB), bThre); // 设置脏标记 pDoc->SetModifiedFlag(TRUE); // 更新视图 pDoc->UpdateAllViews(NULL); /////////////////////////////////////////////////////// // 提取车牌 // 缩放后图像的宽度和高度 LONG lNewWidth = 140; LONG lNewHeight = 40; // 缩放后图像的宽度(lNewWidth',必须是4的倍数) LONG lNewLineBytes; // 创建新DIB HDIB hNewDIB = NULL; // 指向缩放图像的指针 LPSTR lpNewDIB ; // 指向BITMAPINFO结构的指针(Win3.0) LPBITMAPINFOHEADER lpbmi; // 指向BITMAPCOREINFO结构的指针 LPBITMAPCOREHEADER lpbmc; // 计算新图像每行的字节数 lNewLineBytes = WIDTHBYTES(lNewWidth * 8); // 更改光标形状 BeginWaitCursor(); // 找到DIB图像象素起始位置 lpDIBBits = ::FindDIBBits(lpDIB); pPlatePosition = RowscanDIB3 (lpDIBBits,lpNewDIBBits1,::DIBWidth(lpDIB), ::DIBHeight(lpDIB), pPlateLine2); for(i=0;i<5;i++) { m_iPlatePosition[i] = *pPlatePosition; pPlatePosition++; } if(m_iPlatePosition[0]==1) { // AfxMessageBox("找到了!"); // 显示车牌位置信息 // CDlgShowPlate dlgShowPlate; // dlgShowPlate.m_iTop = ::DIBHeight(lpDIB) - m_iPlatePosition[0]; // dlgShowPlate.m_iLow = ::DIBHeight(lpDIB) - m_iPlatePosition[1]; // dlgShowPlate.m_iLeft = m_iPlatePosition[2]; // dlgShowPlate.m_iRight = m_iPlatePosition[3]; // dlgShowPlate.DoModal(); // 分配内存,以保存新DIB hNewDIB = (HDIB) ::GlobalAlloc(GHND, lNewLineBytes * lNewHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB)); // 判断是否内存分配失败 if (hNewDIB != NULL) { lpNewDIB = (char * )::GlobalLock((HGLOBAL) hNewDIB); // 复制DIB信息头、调色板和车牌图像 memcpy(lpNewDIB, lpDIB, *(LPDWORD)lpDIB + ::PaletteSize(lpDIB) + lNewLineBytes * lNewHeight); // 获取指针 lpbmi = (LPBITMAPINFOHEADER)lpNewDIB; lpbmc = (LPBITMAPCOREHEADER)lpNewDIB; // 更新DIB中图像的高度和宽度 if (IS_WIN30_DIB(lpNewDIB)) { // 对于Windows 3.0 DIB lpbmi->biWidth = lNewWidth; lpbmi->biHeight = lNewHeight; } else { // 对于其它格式的DIB lpbmc->bcWidth = (unsigned short) lNewWidth; lpbmc->bcHeight = (unsigned short) lNewHeight; } // TRACE("\n*******%d*******\n",m_iPlatePosition[0]); // 替换DIB,同时释放旧DIB对象 pDoc->ReplaceHDIB(hNewDIB); // 更新DIB大小和调色板 pDoc->InitDIBData(); // 设置脏标记 pDoc->SetModifiedFlag(TRUE); // 更新视图 pDoc->UpdateAllViews(NULL); } } else { // 提示用户 // AfxMessageBox("这次没找到!"); } if( (m_iPlateLine[iLineNumber+2]>=0)||((m_iPlatePosition[0]==1))) break; } // 释放内存 LocalUnlock(hNewDIBBits1); LocalFree(hNewDIBBits1); LocalUnlock(hNewDIBBits2); LocalFree(hNewDIBBits2); // 解除锁定 ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); // 恢复光标 EndWaitCursor(); } void CPlateRecoView::OnLPRplate2binarycolor() { // TODO: Add your command handler code here // 二值化 // 获取文档 CPlateRecoDoc* pDoc = GetDocument(); // 指向DIB的指针 LPSTR lpDIB; // 指向DIB象素指针 LPSTR lpDIBBits; // 参数对话框 //CDlgBinary myDlgBinary; // 阈值 BYTE bThre; // 锁定DIB lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB()); // 找到DIB图像象素起始位置 lpDIBBits = ::FindDIBBits(lpDIB); // 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的阈值变换,其它的可以类推) if (::DIBNumColors(lpDIB) != 256) { // 提示用户 MessageBox("目前只支持256色位图的阈值变换!", "系统提示" , MB_ICONINFORMATION | MB_OK); // 解除锁定 ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); // 返回 return; } // 各个灰度值的计数 LONG lCount[256]; int temp1,temp2,iOldLeixin1,iOldLeixin2,iNum1,iNum2,iGrayCore1,iGrayCore2,iMeanGray; // 指向源图像象素的指针 unsigned char * lpSrc; // 循环变量 LONG i; LONG j; // 重置计数为0 for (i = 0; i < 256; i ++) { // 清零 lCount[i] = 0; } // 车牌图像的长、宽 int iWidth; int iHeight; iWidth = ::DIBWidth(lpDIB); iHeight = ::DIBHeight(lpDIB); // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(iWidth * 8); // 计算各个灰度值的计数 for (i = 0; i < iHeight; i ++) { for (j = 0; j < iWidth; j ++) { lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j; // 计数加1 lCount[*(lpSrc)]++; } } // 计算平均灰度值 iMeanGray = 0; for(i = 1; i < 255; i++) { iMeanGray += i * lCount[i]; } iMeanGray = (int)iMeanGray / (iHeight * iWidth); // 初始的类心,可任意设定 iGrayCore1 = (int)(iMeanGray/2); iGrayCore2 = (int)(iMeanGray+(255-iMeanGray)/2); do // K-均值聚类分析 { iNum1 = 0; iNum2 = 0; temp1 = 0; temp2 = 0; iOldLeixin1 = iGrayCore1; iOldLeixin2 = iGrayCore2; for(i = 0; i < iHeight; i++) { for(j = 0; j < iWidth; j++) { lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j; if(abs(iGrayCore1-*lpSrc)<=abs(iGrayCore2-*lpSrc)) { temp1 += *lpSrc; iNum1++; } else { temp2 += *lpSrc; iNum2++; } } } iGrayCore1 = (int)(temp1/iNum1); iGrayCore2 = (int)(temp2/iNum2); }while((iGrayCore1!=iOldLeixin1)||(iGrayCore2!=iOldLeixin2)); // 初始化变量值 //myDlgBinary.m_bThre = iGrayCore2-20; /* 显示对话框,提示用户设定阈值 if (myDlgBinary.DoModal() != IDOK) { // 返回 return; }*/ // 获取用户设定的阈值 bThre = 112; //myDlgBinary.m_bThre; // 删除对话框 //delete myDlgBinary; // 更改光标形状 BeginWaitCursor(); // 调用ThresholdTrans()函数进行阈值变换 ThresholdTrans(lpDIBBits, ::DIBWidth(lpDIB), ::DIBHeight(lpDIB), bThre); // 设置脏标记 pDoc->SetModifiedFlag(TRUE); // 更新视图 pDoc->UpdateAllViews(NULL); // 解除锁定 ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); // 恢复光标 EndWaitCursor(); } void CPlateRecoView::OnLPRplatenorm() { // TODO: Add your command handler code here // 字符归一化 // 获取文档 CPlateRecoDoc* pDoc = GetDocument(); // 指向DIB的指针 LPSTR lpDIB; // 指向DIB象素指针 LPSTR lpDIBBits; LPSTR lpNewDIBBits2; // 字符归一化后的新的高度与宽度 int iNewWidth; int iOldHeight; int iNewHeight; int* pNewHeight; int iTemp; // 锁定DIB lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB()); iNewWidth = ::DIBWidth(lpDIB); iOldHeight = ::DIBHeight(lpDIB); // 找到DIB图像象素起始位置 lpDIBBits = ::FindDIBBits(lpDIB); // 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的阈值变换,其它的可以类推) if (::DIBNumColors(lpDIB) != 256) { // 提示用户 MessageBox("目前只支持256色位图的阈值变换!", "系统提示" , MB_ICONINFORMATION | MB_OK); // 解除锁定 ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); // 返回 return; } // 更改光标形状 BeginWaitCursor(); pNewHeight = RowscanDIB4(lpDIBBits,::DIBWidth(lpDIB), ::DIBHeight(lpDIB)); iTemp = *pNewHeight; pNewHeight++; iNewHeight = *pNewHeight; iNewHeight = abs(iNewHeight - iTemp); // 缩放后图像的宽度(lNewWidth',必须是4的倍数) LONG lNewLineBytes; // 创建新DIB HDIB hNewDIB = NULL; // 指向缩放图像的指针 LPSTR lpNewDIB ; // 指向缩放图像的指针 LPSTR lpNewDIB2; // 指向BITMAPINFO结构的指针(Win3.0) LPBITMAPINFOHEADER lpbmi; // 指向BITMAPCOREINFO结构的指针 LPBITMAPCOREHEADER lpbmc; // 计算新图像每行的字节数 lNewLineBytes = WIDTHBYTES(iNewWidth * 8); // 分配内存,以保存新DIB hNewDIB = (HDIB) ::GlobalAlloc(GHND, lNewLineBytes * iNewHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB)); // 判断是否内存分配失败 if (hNewDIB != NULL) { lpNewDIB = (char * )::GlobalLock((HGLOBAL) hNewDIB); // 复制DIB信息头、调色板和车牌图像 memcpy(lpNewDIB, lpDIB, *(LPDWORD)lpDIB + ::PaletteSize(lpDIB) + lNewLineBytes * iNewHeight); // 获取指针 lpbmi = (LPBITMAPINFOHEADER)lpNewDIB; lpbmc = (LPBITMAPCOREHEADER)lpNewDIB; // 更新DIB中图像的高度和宽度 if (IS_WIN30_DIB(lpNewDIB)) { // 对于Windows 3.0 DIB lpbmi->biWidth = iNewWidth; lpbmi->biHeight = iNewHeight; } else { // 对于其它格式的DIB lpbmc->bcWidth = (unsigned short) iNewWidth; lpbmc->bcHeight = (unsigned short) iNewHeight; } // TRACE("\n*******%d*******\n",m_iPlatePosition[0]); // 替换DIB,同时释放旧DIB对象 pDoc->ReplaceHDIB(hNewDIB); // 更新DIB大小和调色板 pDoc->InitDIBData(); // 设置脏标记 pDoc->SetModifiedFlag(TRUE); // 更新视图 // pDoc->UpdateAllViews(NULL); } LocalUnlock(lpDIB); LocalFree(lpDIB); // 创建新DIB HDIB hNewDIB2 = NULL; // 更改光标形状 BeginWaitCursor(); float fXZoomRatio = 1.0; float fYZoomRatio; fYZoomRatio = (float)iOldHeight / (float)::DIBHeight(lpNewDIB); // 调用ZoomDIB()函数转置DIB hNewDIB2 = (HDIB) ZoomDIB(lpNewDIB, fXZoomRatio, fYZoomRatio); // 判断缩放是否成功 if (hNewDIB2 != NULL) { // 替换DIB,同时释放旧DIB对象 pDoc->ReplaceHDIB(hNewDIB2); // 更新DIB大小和调色板 pDoc->InitDIBData(); // 设置脏标记 pDoc->SetModifiedFlag(TRUE); lpNewDIB2 = (char * )::GlobalLock((HGLOBAL) hNewDIB2); // 重新设置滚动视图大小 SetScrollSizes(MM_TEXT, pDoc->GetDocSize()); // 更新视图 // pDoc->UpdateAllViews(NULL); } else { // 提示用户 MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION | MB_OK); } LocalUnlock(lpNewDIB); LocalFree(lpNewDIB); // 找到DIB图像象素起始位置 lpNewDIBBits2 = ::FindDIBBits(lpNewDIB2); // 调用ThresholdTrans()函数进行阈值变换 if(CharacterUnit(lpNewDIBBits2, ::DIBWidth(lpNewDIB2), ::DIBHeight(lpNewDIB2)) != TRUE) { return; } // 设置脏标记 pDoc->SetModifiedFlag(TRUE); // 更新视图 pDoc->UpdateAllViews(NULL); // 解除锁定 ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); // 恢复光标 EndWaitCursor(); } void CPlateRecoView::OnLPRplatecharthinning() { // TODO: Add your command handler code here // 获取文档 CPlateRecoDoc* pDoc = GetDocument(); // 指向DIB的指针 LPSTR lpDIB; // 指向DIB象素指针 LPSTR lpDIBBits; // 线性变换的斜率 FLOAT fA; // 线性变换的截距 FLOAT fB; // 反色操作的线性变换的方程是-x + 255 fA = -1.0; fB = 255.0; // 锁定DIB lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB()); // 找到DIB图像象素起始位置 lpDIBBits = ::FindDIBBits(lpDIB); // 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的反色,其它的可以类推) if (::DIBNumColors(lpDIB) != 256) { // 提示用户 MessageBox("目前只支持256色位图的反色!", "系统提示" , MB_ICONINFORMATION | MB_OK); // 解除锁定 ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); // 返回 return; } // 更改光标形状 BeginWaitCursor(); // 调用LinerTrans()函数反色 LinerTrans(lpDIBBits, ::DIBWidth(lpDIB), ::DIBHeight(lpDIB), fA, fB); // 设置脏标记 pDoc->SetModifiedFlag(TRUE); // 更新视图 // pDoc->UpdateAllViews(NULL); // 解除锁定 // ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); // 恢复光标 // EndWaitCursor(); // 找到DIB图像象素起始位置 // lpDIBBits = ::FindDIBBits(lpDIB); // 调用ThiningDIB()函数对DIB进行闭运算 if (ThiningDIB(lpDIBBits, WIDTHBYTES(::DIBWidth(lpDIB) * 8), ::DIBHeight(lpDIB))) { // 设置脏标记 pDoc->SetModifiedFlag(TRUE); // 更新视图 pDoc->UpdateAllViews(NULL); } else { // 提示用户 MessageBox("分配内存失败或者图像中含有0和255之外的像素值!", "系统提示" , MB_ICONINFORMATION | MB_OK); } // 解除锁定 ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); // 恢复光标 EndWaitCursor(); } void CPlateRecoView::OnLPRfeature16seg() { // TODO: Add your command handler code here // 基于13段投影法的特征提取 // 获取文档 CPlateRecoDoc* pDoc = GetDocument(); // 指向DIB的指针 LPSTR lpDIB; // 指向DIB象素指针 LPSTR lpDIBBits; // 锁定DIB lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB()); // 找到DIB图像象素起始位置 lpDIBBits = ::FindDIBBits(lpDIB); // 用于传递13段投影编码表 float* pCode16Section; float fCode16Sect[6][16]; FILE *fpPlateCharData; char *pPlateCharDataFileName = "识别数据_16段映射.txt "; LONG i,j; // 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的沃尔什-哈达玛变换,其它的可以类推) if (::DIBNumColors(lpDIB) != 256) { // 提示用户 MessageBox("目前只支持256色位图的沃尔什-哈达玛变换!", "系统提示" , MB_ICONINFORMATION | MB_OK); // 解除锁定 ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); // 返回 return; } pCode16Section = CharExtract16Sect(lpDIBBits, ::DIBWidth(lpDIB), ::DIBHeight(lpDIB)); // TRACE("\n"); for(i=0;i<6;i++) { for(j=0;j<16;j++) { fCode16Sect[i][j] = *pCode16Section; m_fCode16Sect[i][j] = fCode16Sect[i][j]; pCode16Section++; } // TRACE("\t%f",m_fCode13Sect[i]); } if((fpPlateCharData = fopen(pPlateCharDataFileName,"w+"))==NULL) { AfxMessageBox(" 无法正确创建文件!\n请检查您代码中的文件名!"); return; } int q1=0; // 将提取出的各字符的特征量存成文件 // 将指针移到文件头 fseek(fpPlateCharData,0l,SEEK_SET); for(i = 0; i < 6; i++) { for(j = 0; j < 16; j++) { // fprintf(fpHidWeight,"%f",fHidWeight[i][j]); fprintf(fpPlateCharData,"%10f",fCode16Sect[i][j]); } fprintf(fpPlateCharData,"\n",""); if(i==5) fprintf(fpPlateCharData,"\n",""); } fclose(fpPlateCharData); // TRACE("\n"); // 解除锁定 ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB()); // 更改光标形状 BeginWaitCursor(); } void CPlateRecoView::OnLPRplatereco() { OnLPRfeature16seg(); CPlateRecoDoc* pDoc = GetDocument(); float* pReco16Section; // CString strRecoChars,strTemp; CDlgRecoResult myDlgRecoResult; pReco16Section = &m_fCode16Sect[0][0]; // 字符识别 m_cRecoChar[0] = BPReco16SectionLetter(pReco16Section); pReco16Section = &m_fCode16Sect[1][0]; if(m_iPlateType==0) { m_cRecoChar[1] = BPReco16SectionLetter(pReco16Section); } else { m_cRecoChar[1] = BPReco16SectionNumber(pReco16Section); } // strTemp.Format("%c",m_cRecoChar[0]); pReco16Section = &m_fCode16Sect[2][0]; m_cRecoChar[2] = BPReco16SectionNumber(pReco16Section); pReco16Section = &m_fCode16Sect[3][0]; m_cRecoChar[3] = BPReco16SectionNumber(pReco16Section); pReco16Section = &m_fCode16Sect[4][0]; m_cRecoChar[4] = BPReco16SectionNumber(pReco16Section); pReco16Section = &m_fCode16Sect[5][0]; m_cRecoChar[5] = BPReco16SectionNumber(pReco16Section); myDlgRecoResult.m_cRecoChar[0]= m_cRecoChar[0]; myDlgRecoResult.m_cRecoChar[1]= m_cRecoChar[1]; myDlgRecoResult.m_cRecoChar[2]= m_cRecoChar[2]; myDlgRecoResult.m_cRecoChar[3]= m_cRecoChar[3]; myDlgRecoResult.m_cRecoChar[4]= m_cRecoChar[4]; myDlgRecoResult.m_cRecoChar[5]= m_cRecoChar[5]; myDlgRecoResult.DoModal(); delete myDlgRecoResult; return; } void CPlateRecoView::OnLPRplatepreprocessall() { OnLPRplatelocation(); OnLPRplate2binarycolor(); OnLPRplatenorm(); OnLPRplatecharthinning(); }